前一陣子看到新版 Firefox 102 版開始,可以讓使用者決定是不是要把網址中的一些 query parameters 過濾掉,常見的像是 facebook 的 id 追蹤 fbclid
,還有 Google 的 ga_*
, gclid
等;還有在追蹤活動時很常用的 utm_*
系列。如果這些足跡能在瀏覽網頁時去除掉,對於自己的隱私可以多一層保障。
所以,我也打算在 EinkBro 中來實作一下。這個功能主要可以分成兩部份:第一部份是取得哪些是應該要過濾掉的 query parameters,將它們用適當的方式儲存下來;第二部份才是透過跟網址比對,決定哪些參數需要清除,哪些是正常的,需要保留下來。
一開始,並沒有找到 Firefox 的實作方式,所以先在 Github 上找了其他 Open Source 的 repository 來參考。第一步是先將這個 Neat-URL 的資料納為己用。它的資料中已經有列了很多常見網站的各種追蹤參數;有些是可以套在所有網站上的,有些是特定網站才會冒出來的參數。我先將這份 json 檔案存到了程式中,並且在 EinkBro 一開始執行的時候,就把下面的 params 存到了一個 List 中。每次要載入 url 時,都會去跟這些 params 做比較,如果有符合格式的話,就將其排除。
裡頭的資料大概長這樣:
{
"categories": [
{ "name": "Amazon", "params": ["_encoding@amazon.*", "ascsubtag@amazon.*", "pd_rd_*@amazon.*", "pf@amazon.*", "pf_rd_*@amazon.*", "psc@amazon.*", "ref_@amazon.*", "tag@amazon.*"]},
{ "name": "Bilibili.com", "params": ["callback@bilibili.com"]},
{ "name": "Bing", "params": ["cvid@bing.com", "form@bing.com", "pq@bing.com", "qs@bing.com", "sc@bing.com", "sk@bing.com", "sp@bing.com"]},
{ "name": "Campaign tracking (Adobe Analytics)", "params": ["sc_cid"]},
{ "name": "Campaign tracking (Google Analytics, ga)", "params": ["ga_*", "gclid", "gclsrc"]},
{ "name": "Facebook", "params": ["fb_action_ids", "fb_action_types", "fb_ref", "fb_source", "fbclid", "hrc@facebook.com", "refsrc@facebook.com"]},
{ "name": "Google", "params": ["ei@google.*", "gs_gbg@google.*", "gs_l", "gs_lcp@google.*", "gs_mss@google.*", "gs_rn@google.*", "gws_rd@google.*", "sei@google.*", "ved@google.*"]},
{ "name": "LinkedIn", "params": ["eBP@linkedin.com", "lgCta@linkedin.com", "lgTemp@linkedin.com", "lipi@linkedin.com", "midSig@linkedin.com", "midToken@linkedin.com", "recommendedFlavor@linkedin.com", "refId@linkedin.com", "trackingId@linkedin.com", "trk@linkedin.com", "trkEmail@linkedin.com"]},
{ "name": "Medium", "params": ["_branch_match_id@medium.com", "source@medium.com"]},
{ "name": "TikTok", "params": ["_d@tiktok.com", "checksum@tiktok.com", "is_copy_url@tiktok.com", "is_from_webapp@tiktok.com", "language@tiktok.com", "preview_pb@tiktok.com", "sec_user_id@tiktok.com", "sender_device@tiktok.com", "sender_web_id@tiktok.com", "share_app_id@tiktok.com", "share_link_id@tiktok.com", "share_item_id@tiktok.com", "source@tiktok.com", "timestamp@tiktok.com", "tt_from@tiktok.com", "u_code@tiktok.com", "user_id@tiktok.com"]},
{ "name": "Twitch.tv", "params": ["tt_content", "tt_medium"]},
{ "name": "Twitter", "params": ["cxt@*.twitter.com", "ref_*@*.twitter.com", "s@*.twitter.com", "t@*.twitter.com", "twclid"]},
]
}
目前判斷的邏輯還沒全部完成,但至少通用型的參數,目前都可以過濾掉了。實做方式大致如下:
有了個別的參數比對函式後,再來是將 url string 分解成 Uri ,將裡頭的 query parameters 一個個拿出來做比較:
完成後,再來就是把會用到網址的地方加上上述的邏輯。主要有兩個地方,一個是在 loadUrl 時,這時候的 url 有可能是使用者從外部其他 App 帶進來的,我不想讓它在 EinkBro 發出網頁 request 時順便也送出這些參數;所以在 loadUrl 時,可以做這個處理。
另一個地方是,在 EinkBro 中,要把當下網站的某些網頁連結分享到別的 App 去時;這時候網站給出來的網頁連結也有可能是塞滿追蹤碼的。為了讓其他 App 不要也拿到被追蹤的連結,在這個時間點也可以先處理過再把連結傳送出去。
少了一堆追蹤碼後,心裡就更踏實了!
不過,要注意一點是:有時有些網站(像是購物網站)的活動會利用上面講的某些 query parameters 來記錄,如果全部都濾掉的話,反而會被認為是沒有符合規定的使用者。所以,我在 EinkBro 設定頁面裡增加了一個選項,讓使用者可以自己開關"過濾追蹤碼"的功能,而且預設是關閉的,避免影響到不知情的使用者的使用場景。
在套用 Neat-Url 的作法時,我還是繼續想要找出 Firefox 的實作方式。原先以為它會是用 Android 的 kotlin 撰寫的,結果發現我的尋找方向錯誤:這功能實際上是用 C++ 開發的。連結在此。
另外,也意外地找到了 Brave Browser 中的實作方式。但是,Brave Browser 的實作方式比較陽春就是了。,它會處理的資料如下:
static constexpr auto kSimpleQueryStringTrackers =
base::MakeFixedFlatSet<base::StringPiece>(
{// https://github.com/brave/brave-browser/issues/4239
"fbclid", "gclid", "msclkid", "mc_eid",
// https://github.com/brave/brave-browser/issues/9879
"dclid",
// https://github.com/brave/brave-browser/issues/13644
"oly_anon_id", "oly_enc_id",
// https://github.com/brave/brave-browser/issues/11579
"_openstat",
// https://github.com/brave/brave-browser/issues/11817
"vero_conv", "vero_id",
// https://github.com/brave/brave-browser/issues/13647
"wickedid",
// https://github.com/brave/brave-browser/issues/11578
"yclid",
// https://github.com/brave/brave-browser/issues/8975
"__s",
// https://github.com/brave/brave-browser/issues/17451
"rb_clickid",
// https://github.com/brave/brave-browser/issues/17452
"s_cid",
// https://github.com/brave/brave-browser/issues/17507
"ml_subscriber", "ml_subscriber_hash",
// https://github.com/brave/brave-browser/issues/18020
"twclid",
// https://github.com/brave/brave-browser/issues/18758
"gbraid", "wbraid",
// https://github.com/brave/brave-browser/issues/9019
"_hsenc", "__hssc", "__hstc", "__hsfp", "hsCtaTracking",
// https://github.com/brave/brave-browser/issues/22082
"oft_id", "oft_k", "oft_lk", "oft_d", "oft_c", "oft_ck", "oft_ids",
"oft_sk",
// https://github.com/brave/brave-browser/issues/24988
"ss_email_id",
// https://github.com/brave/brave-browser/issues/25238
"bsft_uid", "bsft_clkid",
// https://github.com/brave/brave-browser/issues/11580
"igshid"});